home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / f_rotate2.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  23.9 KB  |  956 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include "VirtualDub.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <crtdbg.h>
  22. #include <math.h>
  23.  
  24. #include <windows.h>
  25. #include <commctrl.h>
  26.  
  27. #include "ScriptInterpreter.h"
  28. #include "ScriptValue.h"
  29. #include "ScriptError.h"
  30.  
  31. #include "resource.h"
  32. #include "filter.h"
  33. #include "cpuaccel.h"
  34. #include "resample.h"
  35. #include "gui.h"
  36.  
  37. /////////////////////////////////////////////////////////////////////
  38.  
  39. #define USE_ASM
  40.  
  41. /////////////////////////////////////////////////////////////////////
  42.  
  43. extern HINSTANCE g_hInst;
  44.  
  45. typedef struct RotateRow {
  46.     int leftzero, left, right, rightzero;
  47.     __int64 xaccum_left, yaccum_left;
  48. } RotateRow;
  49.  
  50. typedef struct MyFilterData {
  51.     int angle;
  52.     int filtmode;
  53.  
  54.     // working variables
  55.  
  56.     IFilterPreview *ifp;
  57.  
  58.     __int64    u_step;
  59.     __int64    v_step;
  60.  
  61.     RotateRow *rows;
  62.     int *coeff_tbl;
  63.  
  64.     COLORREF    rgbColor;
  65.     HBRUSH        hbrColor;
  66.  
  67.     bool    fExpandBounds;
  68.     
  69. } MyFilterData;
  70.  
  71. static const char *const szModeStrings[]={
  72.     "point",
  73.     "bilinear",
  74.     "bicubic"
  75. };
  76.  
  77. enum {
  78.     FILTMODE_POINT        = 0,
  79.     FILTMODE_BILINEAR,
  80.     FILTMODE_BICUBIC,
  81.     FILTMODE_COUNT
  82. };
  83.  
  84. /////////////////////////////////////////////////////////////////////
  85.  
  86. extern "C" void asm_rotate_point(
  87.         Pixel *src,
  88.         Pixel *dst,
  89.         long width,
  90.         long Ufrac,
  91.         long Vfrac,
  92.         long UVintstepV,
  93.         long UVintstepnoV,
  94.         long Ustep,
  95.         long Vstep);
  96.  
  97. extern "C" void asm_rotate_bilinear(
  98.         Pixel *src,
  99.         Pixel *dst,
  100.         long width,
  101.         long pitch,
  102.         long Ufrac,
  103.         long Vfrac,
  104.         long UVintstepV,
  105.         long UVintstepnoV,
  106.         long Ustep,
  107.         long Vstep);
  108.  
  109. /////////////////////////////////////////////////////////////////////
  110.  
  111. static Pixel32 bilinear_interp(Pixel32 c1, Pixel32 c2, Pixel32 c3, Pixel32 c4, unsigned long cox, unsigned long coy) {
  112.     int co1, co2, co3, co4;
  113.  
  114.     co4 = (cox * coy) >> 8;
  115.     co3 = coy - co4;
  116.     co2 = cox - co4;
  117.     co1 = 0x100 - coy - co2;
  118.  
  119.     return   ((((c1 & 0x00FF00FF)*co1 + (c2 & 0x00FF00FF)*co2 + (c3 & 0x00FF00FF)*co3 + (c4 & 0x00FF00FF)*co4)>>8)&0x00FF00FF)
  120.            + ((((c1 & 0x0000FF00)*co1 + (c2 & 0x0000FF00)*co2 + (c3 & 0x0000FF00)*co3 + (c4 & 0x0000FF00)*co4)&0x00FF0000)>>8);
  121. }
  122.  
  123. #define RED(x) ((signed long)((x)>>16)&255)
  124. #define GRN(x) ((signed long)((x)>> 8)&255)
  125. #define BLU(x) ((signed long)(x)&255)
  126.  
  127. static inline Pixel cc(const Pixel *yptr, const int *tbl) {
  128.     const Pixel y1 = yptr[0];
  129.     const Pixel y2 = yptr[1];
  130.     const Pixel y3 = yptr[2];
  131.     const Pixel y4 = yptr[3];
  132.     long red, grn, blu;
  133.  
  134.     red = RED(y1)*tbl[0] + RED(y2)*tbl[1] + RED(y3)*tbl[2] + RED(y4)*tbl[3];
  135.     grn = GRN(y1)*tbl[0] + GRN(y2)*tbl[1] + GRN(y3)*tbl[2] + GRN(y4)*tbl[3];
  136.     blu = BLU(y1)*tbl[0] + BLU(y2)*tbl[1] + BLU(y3)*tbl[2] + BLU(y4)*tbl[3];
  137.  
  138.     if (red<0) red=0; else if (red>4194303) red=4194303;
  139.     if (grn<0) grn=0; else if (grn>4194303) grn=4194303;
  140.     if (blu<0) blu=0; else if (blu>4194303) blu=4194303;
  141.  
  142.     return ((red<<2) & 0xFF0000) | ((grn>>6) & 0x00FF00) | (blu>>14);
  143. }
  144.  
  145. #undef RED
  146. #undef GRN
  147. #undef BLU
  148.  
  149. static Pixel32 __declspec(naked) cc_MMX(const Pixel32 *src, const int *table) {
  150.  
  151.     static const __int64 x0000200000002000 = 0x0000200000002000i64;
  152.  
  153.     //    [esp + 4]    src
  154.     //    [esp + 8]    table
  155.  
  156.     _asm {
  157.         mov            ecx,[esp+4]
  158.         mov            eax,[esp+8]
  159.  
  160.         movd        mm0,[ecx]
  161.         pxor        mm7,mm7
  162.  
  163.         movd        mm1,[ecx+4]
  164.         punpcklbw    mm0,mm7                ;mm0 = [a1][r1][g1][b1]
  165.  
  166.         movd        mm2,[ecx+8]
  167.         punpcklbw    mm1,mm7                ;mm1 = [a2][r2][g2][b2]
  168.  
  169.         movd        mm3,[ecx+12]
  170.         punpcklbw    mm2,mm7                ;mm2 = [a3][r3][g3][b3]
  171.  
  172.         punpcklbw    mm3,mm7                ;mm3 = [a4][r4][g4][b4]
  173.         movq        mm4,mm0                ;mm0 = [a1][r1][g1][b1]
  174.  
  175.         punpcklwd    mm0,mm1                ;mm0 = [g2][g1][b2][b1]
  176.         movq        mm5,mm2                ;mm2 = [a3][r3][g3][b3]
  177.  
  178.         pmaddwd        mm0,[eax]
  179.         punpcklwd    mm2,mm3                ;mm2 = [g4][g3][b4][b3]
  180.  
  181.         pmaddwd        mm2,[eax+8]
  182.         punpckhwd    mm4,mm1                ;mm4 = [a2][a1][r2][r1]
  183.  
  184.         pmaddwd        mm4,[eax]
  185.         punpckhwd    mm5,mm3                ;mm5 = [a4][a3][b4][b3]
  186.  
  187.         pmaddwd        mm5,[eax+8]
  188.         paddd        mm0,mm2                ;mm0 = [ g ][ b ]
  189.  
  190.         paddd        mm0,x0000200000002000
  191.         ;idle V
  192.  
  193.         paddd        mm4,x0000200000002000
  194.         psrad        mm0,14
  195.  
  196.         paddd        mm4,mm5                ;mm4 = [ a ][ r ]
  197.  
  198.         psrad        mm4,14
  199.  
  200.         packssdw    mm0,mm4                ;mm0 = [ a ][ r ][ g ][  b ]
  201.         packuswb    mm0,mm0                ;mm0 = [a][r][g][b][a][r][g][b]
  202.  
  203.         movd        eax,mm0
  204.         ret
  205.     }
  206. }
  207.  
  208. static inline Pixel32 bicubic_interp_MMX(const Pixel32 *src, PixOffset pitch, unsigned long cox, unsigned long coy, const int *table) {
  209.     Pixel32 x[4];
  210.  
  211.     cox >>= 24;
  212.     coy >>= 24;
  213.  
  214.     src = (Pixel32 *)((char *)src - pitch - 4);
  215.  
  216.     x[0] = cc_MMX(src, table+cox*4); src = (Pixel32 *)((char *)src + pitch);
  217.     x[1] = cc_MMX(src, table+cox*4); src = (Pixel32 *)((char *)src + pitch);
  218.     x[2] = cc_MMX(src, table+cox*4); src = (Pixel32 *)((char *)src + pitch);
  219.     x[3] = cc_MMX(src, table+cox*4);
  220.  
  221.     return cc_MMX(x, table + coy*4);
  222. }
  223.  
  224. static inline Pixel32 bicubic_interp(const Pixel32 *src, PixOffset pitch, unsigned long cox, unsigned long coy, const int *table) {
  225.     Pixel32 x[4];
  226.  
  227.     cox >>= 24;
  228.     coy >>= 24;
  229.  
  230.     src = (Pixel32 *)((char *)src - pitch - 4);
  231.  
  232.     x[0] = cc(src, table+cox*4); src = (Pixel32 *)((char *)src + pitch);
  233.     x[1] = cc(src, table+cox*4); src = (Pixel32 *)((char *)src + pitch);
  234.     x[2] = cc(src, table+cox*4); src = (Pixel32 *)((char *)src + pitch);
  235.     x[3] = cc(src, table+cox*4);
  236.  
  237.     return cc(x, table + coy*4);
  238. }
  239.  
  240. static Pixel32 ColorRefToPixel32(COLORREF rgb) {
  241.     return (Pixel32)(((rgb>>16)&0xff) | ((rgb<<16)&0xff0000) | (rgb&0xff00));
  242. }
  243.  
  244. static int rotate2_run(const FilterActivation *fa, const FilterFunctions *ff) {
  245.     const MyFilterData *mfd = (MyFilterData *)fa->filter_data;
  246.     __int64 xaccum, yaccum;
  247.     Pixel32 *src, *dst, pixFill;
  248.     PixDim w, h;
  249.     const RotateRow *rr = mfd->rows;
  250.     const __int64 du = mfd->u_step;
  251.     const __int64 dv = mfd->v_step;
  252.  
  253.     unsigned long Ustep, Vstep;
  254.     unsigned long UVintstepV, UVintstepnoV;
  255.  
  256.     // initialize Abrash texmapping variables :)
  257.  
  258.     Ustep = (unsigned long)du;
  259.     Vstep = (unsigned long)dv;
  260.  
  261.     UVintstepnoV = (long)(du>>32) + (long)(dv>>32)*(fa->src.pitch>>2);
  262.     UVintstepV = UVintstepnoV + (fa->src.pitch>>2);
  263.  
  264.     dst = fa->dst.data;
  265.     pixFill = ColorRefToPixel32(mfd->rgbColor);
  266.  
  267.     h = fa->dst.h;
  268.     do {
  269.         // texmap!
  270.  
  271.         w = rr->leftzero;
  272.         if (w) do {
  273.             *dst++ = pixFill;
  274.         } while(--w);
  275.  
  276.         xaccum = rr->xaccum_left;
  277.         yaccum = rr->yaccum_left;
  278.  
  279.         switch(mfd->filtmode) {
  280.         case FILTMODE_POINT:
  281.             w = fa->dst.w - (rr->leftzero + rr->left + rr->right + rr->rightzero);
  282.             if (w) {
  283.  
  284. #ifdef USE_ASM
  285.                 asm_rotate_point(
  286.                     (Pixel32*)((char *)fa->src.data + (int)(xaccum>>32)*4 + (int)(yaccum>>32)*fa->src.pitch),
  287.                     dst,
  288.                     w,
  289.                     (unsigned long)xaccum,
  290.                     (unsigned long)yaccum,
  291.                     UVintstepV,
  292.                     UVintstepnoV,
  293.                     Ustep,
  294.                     Vstep);
  295.  
  296.                 dst += w;
  297.  
  298. #else
  299.                 do {
  300.                     *dst++ = *(Pixel32*)((char *)fa->src.data + (int)(xaccum>>32)*4 + (int)(yaccum>>32)*fa->src.pitch);
  301.  
  302.                     xaccum += du;
  303.                     yaccum += dv;
  304.                 } while(--w);
  305. #endif
  306.                 break;
  307.             }
  308.  
  309.         case FILTMODE_BILINEAR:
  310.             w = rr->left;
  311.             if (w) {
  312.                 do {
  313.                     Pixel32 *src = (Pixel32*)((char *)fa->src.data + (int)(xaccum>>32)*4 + (int)(yaccum>>32)*fa->src.pitch);
  314.                     Pixel32 c1, c2, c3, c4;
  315.  
  316.                     int px = (int)(xaccum >> 32);
  317.                     int py = (int)(yaccum >> 32);
  318.  
  319.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  320.                         c1 = pixFill;
  321.                     else
  322.                         c1 = *(Pixel32 *)((char *)src + 0);
  323.  
  324.                     ++px;
  325.  
  326.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  327.                         c2 = pixFill;
  328.                     else
  329.                         c2 = *(Pixel32 *)((char *)src + 4);
  330.  
  331.                     ++py;
  332.  
  333.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  334.                         c4 = pixFill;
  335.                     else
  336.                         c4 = *(Pixel32 *)((char *)src + 4 + fa->src.pitch);
  337.  
  338.                     --px;
  339.  
  340.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  341.                         c3 = pixFill;
  342.                     else
  343.                         c3 = *(Pixel32 *)((char *)src + 0 + fa->src.pitch);
  344.  
  345.                     *dst++ = bilinear_interp(c1, c2, c3, c4, (unsigned long)xaccum >> 24, (unsigned long)yaccum >> 24);
  346.  
  347.                     xaccum += du;
  348.                     yaccum += dv;
  349.                 } while(--w);
  350.             }
  351.  
  352.             w = fa->dst.w - (rr->leftzero + rr->left + rr->right + rr->rightzero);
  353.             if (w) {
  354. #ifdef USE_ASM
  355.                 asm_rotate_bilinear(
  356.                         (Pixel32*)((char *)fa->src.data + (int)(xaccum>>32)*4 + (int)(yaccum>>32)*fa->src.pitch),
  357.                         dst,
  358.                         w,
  359.                         fa->src.pitch,
  360.                         (unsigned long)xaccum,
  361.                         (unsigned long)yaccum,
  362.                         UVintstepV,
  363.                         UVintstepnoV,
  364.                         Ustep,
  365.                         Vstep);
  366.  
  367.                 xaccum += du*w;
  368.                 yaccum += dv*w;
  369.                 dst += w;
  370. #else
  371.                 do {
  372.                     Pixel32 *src = (Pixel32*)((char *)fa->src.data + (int)(xaccum>>32)*4 + (int)(yaccum>>32)*fa->src.pitch);
  373.                     Pixel32 c1, c2, c3, c4, cY;
  374.                     int co1, co2, co3, co4, cox, coy;
  375.  
  376.                     c1 = *(Pixel32 *)((char *)src + 0);
  377.                     c2 = *(Pixel32 *)((char *)src + 4);
  378.                     c3 = *(Pixel32 *)((char *)src + 0 + fa->src.pitch);
  379.                     c4 = *(Pixel32 *)((char *)src + 4 + fa->src.pitch);
  380.  
  381.                     cox = ((unsigned long)xaccum >> 24);
  382.                     coy = ((unsigned long)yaccum >> 24);
  383.  
  384.                     co4 = (cox * coy) >> 8;
  385.                     co3 = coy - co4;
  386.                     co2 = cox - co4;
  387.                     co1 = 0x100 - coy - co2;
  388.  
  389.                     cY = ((((c1 & 0x00FF00FF)*co1 + (c2 & 0x00FF00FF)*co2 + (c3 & 0x00FF00FF)*co3 + (c4 & 0x00FF00FF)*co4)>>8)&0x00FF00FF)
  390.                        + ((((c1 & 0x0000FF00)*co1 + (c2 & 0x0000FF00)*co2 + (c3 & 0x0000FF00)*co3 + (c4 & 0x0000FF00)*co4)&0x00FF0000)>>8);
  391.  
  392.                     *dst++ = cY;
  393.  
  394.                     xaccum += du;
  395.                     yaccum += dv;
  396.                 } while(--w);
  397. #endif
  398.             }
  399.  
  400.             w = rr->right;
  401.             if (w) {
  402.                 do {
  403.                     Pixel32 *src = (Pixel32*)((char *)fa->src.data + (int)(xaccum>>32)*4 + (int)(yaccum>>32)*fa->src.pitch);
  404.                     Pixel32 c1, c2, c3, c4;
  405.  
  406.                     int px = (int)(xaccum >> 32);
  407.                     int py = (int)(yaccum >> 32);
  408.  
  409.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  410.                         c1 = pixFill;
  411.                     else
  412.                         c1 = *(Pixel32 *)((char *)src + 0);
  413.  
  414.                     ++px;
  415.  
  416.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  417.                         c2 = pixFill;
  418.                     else
  419.                         c2 = *(Pixel32 *)((char *)src + 4);
  420.  
  421.                     ++py;
  422.  
  423.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  424.                         c4 = pixFill;
  425.                     else
  426.                         c4 = *(Pixel32 *)((char *)src + 4 + fa->src.pitch);
  427.  
  428.                     --px;
  429.  
  430.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  431.                         c3 = pixFill;
  432.                     else
  433.                         c3 = *(Pixel32 *)((char *)src + 0 + fa->src.pitch);
  434.  
  435.                     *dst++ = bilinear_interp(c1, c2, c3, c4, (unsigned long)xaccum >> 24, (unsigned long)yaccum >> 24);
  436.  
  437.                     xaccum += du;
  438.                     yaccum += dv;
  439.                 } while(--w);
  440.             }
  441.             break;
  442.  
  443.         case FILTMODE_BICUBIC:
  444.             w = rr->left;
  445.             if (w) {
  446.                 do {
  447.                     Pixel32 *src = (Pixel32*)((char *)fa->src.data + (int)(xaccum>>32)*4 + (int)(yaccum>>32)*fa->src.pitch);
  448.                     Pixel32 c1, c2, c3, c4;
  449.  
  450.                     int px = (int)(xaccum >> 32);
  451.                     int py = (int)(yaccum >> 32);
  452.  
  453.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  454.                         c1 = pixFill;
  455.                     else
  456.                         c1 = *(Pixel32 *)((char *)src + 0);
  457.  
  458.                     ++px;
  459.  
  460.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  461.                         c2 = pixFill;
  462.                     else
  463.                         c2 = *(Pixel32 *)((char *)src + 4);
  464.  
  465.                     ++py;
  466.  
  467.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  468.                         c4 = pixFill;
  469.                     else
  470.                         c4 = *(Pixel32 *)((char *)src + 4 + fa->src.pitch);
  471.  
  472.                     --px;
  473.  
  474.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  475.                         c3 = pixFill;
  476.                     else
  477.                         c3 = *(Pixel32 *)((char *)src + 0 + fa->src.pitch);
  478.  
  479.                     *dst++ = bilinear_interp(c1, c2, c3, c4, (unsigned long)xaccum >> 24, (unsigned long)yaccum >> 24);
  480.  
  481.                     xaccum += du;
  482.                     yaccum += dv;
  483.                 } while(--w);
  484.             }
  485.  
  486.             w = fa->dst.w - (rr->leftzero + rr->left + rr->right + rr->rightzero);
  487.             if (w) {
  488.                 __int64 xa = xaccum;
  489.                 __int64 ya = yaccum;
  490.  
  491.                 src = (Pixel32*)((char *)fa->src.data + (int)(xa>>32)*4 + (int)(ya>>32)*fa->src.pitch);
  492.  
  493.                 xaccum += du * w;
  494.                 yaccum += dv * w;
  495.  
  496.                 if (MMX_enabled)
  497.                     do {
  498.                         *dst++ = bicubic_interp_MMX(src, fa->src.pitch, (unsigned long)xa, (unsigned long)ya, mfd->coeff_tbl);
  499.  
  500.                         xa = (__int64)(unsigned long)xa + Ustep;
  501.                         ya = (__int64)(unsigned long)ya + Vstep;
  502.  
  503.                         src += (xa>>32) + (ya>>32 ? UVintstepV : UVintstepnoV);
  504.  
  505.                         xa = (unsigned long)xa;
  506.                         ya = (unsigned long)ya;
  507.                     } while(--w);
  508.                 else
  509.                     do {
  510.                         *dst++ = bicubic_interp(src, fa->src.pitch, (unsigned long)xa, (unsigned long)ya, mfd->coeff_tbl);
  511.  
  512.                         xa = (__int64)(unsigned long)xa + Ustep;
  513.                         ya = (__int64)(unsigned long)ya + Vstep;
  514.  
  515.                         src += (xa>>32) + (ya>>32 ? UVintstepV : UVintstepnoV);
  516.  
  517.                         xa = (unsigned long)xa;
  518.                         ya = (unsigned long)ya;
  519.                     } while(--w);
  520.  
  521.             }
  522.  
  523.             w = rr->right;
  524.             if (w) {
  525.                 do {
  526.                     Pixel32 *src = (Pixel32*)((char *)fa->src.data + (int)(xaccum>>32)*4 + (int)(yaccum>>32)*fa->src.pitch);
  527.                     Pixel32 c1, c2, c3, c4;
  528.  
  529.                     int px = (int)(xaccum >> 32);
  530.                     int py = (int)(yaccum >> 32);
  531.  
  532.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  533.                         c1 = pixFill;
  534.                     else
  535.                         c1 = *(Pixel32 *)((char *)src + 0);
  536.  
  537.                     ++px;
  538.  
  539.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  540.                         c2 = pixFill;
  541.                     else
  542.                         c2 = *(Pixel32 *)((char *)src + 4);
  543.  
  544.                     ++py;
  545.  
  546.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  547.                         c4 = pixFill;
  548.                     else
  549.                         c4 = *(Pixel32 *)((char *)src + 4 + fa->src.pitch);
  550.  
  551.                     --px;
  552.  
  553.                     if (px<0 || py<0 || px>=fa->src.w || py>=fa->src.h)
  554.                         c3 = pixFill;
  555.                     else
  556.                         c3 = *(Pixel32 *)((char *)src + 0 + fa->src.pitch);
  557.  
  558.                     *dst++ = bilinear_interp(c1, c2, c3, c4, (unsigned long)xaccum >> 24, (unsigned long)yaccum >> 24);
  559.  
  560.                     xaccum += du;
  561.                     yaccum += dv;
  562.                 } while(--w);
  563.             }
  564.             break;
  565.         }
  566.  
  567.         w = rr->rightzero;
  568.         if (w) do {
  569.             *dst++ = pixFill;
  570.         } while(--w);
  571.  
  572.         dst = (Pixel32 *)((char *)dst + fa->dst.modulo);
  573.  
  574.         ++rr;
  575.  
  576.     } while(--h);
  577.  
  578.     if (MMX_enabled)
  579.         __asm emms
  580.  
  581.     return 0;
  582. }
  583.  
  584. static long rotate2_param(FilterActivation *fa, const FilterFunctions *ff) {
  585.     MyFilterData *mfd = (MyFilterData *)fa->filter_data;
  586.     int destw, desth;
  587.  
  588.     if (mfd->fExpandBounds) {
  589.         double ang = mfd->angle * (3.14159265358979323846 / 2147483648.0);
  590.         double xcos = cos(ang);
  591.         double xsin = sin(ang);
  592.         int destw1, destw2, desth1, desth2;
  593.  
  594.         // Because the rectangle is symmetric, we only
  595.         // need to rotate two corners and pick the farthest.
  596.  
  597.         destw1 = (int)(0.5 + fabs(fa->dst.w * xcos - fa->dst.h * xsin));
  598.         desth1 = (int)(0.5 + fabs(fa->dst.h * xcos + fa->dst.w * xsin));
  599.         destw2 = (int)(0.5 + fabs(fa->dst.w * xcos + fa->dst.h * xsin));
  600.         desth2 = (int)(0.5 + fabs(fa->dst.h * xcos - fa->dst.w * xsin));
  601.  
  602.         destw = max(destw1, destw2);
  603.         desth = max(desth1, desth2);
  604.     } else {
  605.         destw = fa->dst.w;
  606.         desth = fa->dst.h;
  607.     }
  608.  
  609.     fa->dst.w = destw;
  610.     fa->dst.h = desth;
  611.     fa->dst.AlignTo8();
  612.  
  613.     return FILTERPARAM_SWAP_BUFFERS;
  614. }
  615.  
  616. static BOOL APIENTRY rotate2DlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam) {
  617.     static const char * const szModes[]={
  618.         "Point sampling",
  619.         "Bilinear - 2x2",
  620.         "Bicubic - 4x4",
  621.     };
  622.  
  623.     MyFilterData *mfd = (struct MyFilterData *)GetWindowLong(hDlg, DWL_USER);
  624.     HWND hwndItem;
  625.  
  626.     switch (message)
  627.     {
  628.         case WM_INITDIALOG:
  629.             {
  630.                 char buf[32];
  631.                 int i;
  632.  
  633.                 mfd = (struct MyFilterData *)lParam;
  634.                 SetWindowLong(hDlg, DWL_USER, lParam);
  635.  
  636.                 sprintf(buf, "%.3f", (double)mfd->angle * (360.0 / 4294967296.0));
  637.                 SetDlgItemText(hDlg, IDC_ANGLE, buf);
  638.  
  639.                 hwndItem = GetDlgItem(hDlg, IDC_FILTERMODE);
  640.  
  641.                 for(i=0; i<sizeof szModes/sizeof szModes[0]; i++)
  642.                     SendMessage(hwndItem, CB_ADDSTRING, 0, (LPARAM)szModes[i]);
  643.  
  644.                 SendMessage(hwndItem, CB_SETCURSEL, mfd->filtmode, 0);
  645.  
  646.                 CheckDlgButton(hDlg, IDC_EXPANDBOUNDS, mfd->fExpandBounds);
  647.  
  648.                 mfd->hbrColor = CreateSolidBrush(mfd->rgbColor);
  649.  
  650.                 mfd->ifp->InitButton(GetDlgItem(hDlg, IDC_PREVIEW));
  651.  
  652.             }
  653.             return (TRUE);
  654.  
  655.         case WM_COMMAND:     
  656.             switch(LOWORD(wParam)) {
  657.             case IDOK:
  658.                 mfd->ifp->Close();
  659.                 EndDialog(hDlg, 0);
  660.                 return TRUE;
  661.  
  662.             case IDCANCEL:
  663.                 mfd->ifp->Close();
  664.                 EndDialog(hDlg, 1);
  665.                 return TRUE;
  666.  
  667.             case IDC_PREVIEW:
  668.                 mfd->ifp->Toggle(hDlg);
  669.                 return TRUE;
  670.  
  671.             case IDC_ANGLE:
  672.                 if (HIWORD(wParam) == EN_KILLFOCUS) {
  673.                     char buf[32];
  674.                     double ang;
  675.  
  676.                     if (!GetDlgItemText(hDlg, IDC_ANGLE, buf, sizeof buf)
  677.                         || 1!=sscanf(buf, "%lf", &ang)) {
  678.  
  679.                         MessageBeep(MB_ICONEXCLAMATION);
  680.                         SetFocus(GetDlgItem(hDlg, IDC_ANGLE));
  681.                         return TRUE;
  682.                     }
  683.  
  684.                     ang *= (1.0 / 360.0);
  685.                     ang -= floor(ang);
  686.  
  687.                     mfd->ifp->UndoSystem();
  688.                     mfd->angle = (int)floor((ang - 0.5) * 4294967296.0 + 0.5) ^ 0x80000000;
  689.                     mfd->ifp->RedoSystem();
  690.                 }
  691.                 return TRUE;
  692.  
  693.             case IDC_FILTERMODE:
  694.                 if (HIWORD(wParam) == CBN_SELCHANGE) {
  695.                     mfd->ifp->UndoSystem();
  696.                     mfd->filtmode = SendDlgItemMessage(hDlg, IDC_FILTERMODE, CB_GETCURSEL, 0, 0);
  697.                     mfd->ifp->RedoSystem();
  698.                 }
  699.                 return TRUE;
  700.  
  701.             case IDC_EXPANDBOUNDS:
  702.                 mfd->ifp->UndoSystem();
  703.                 mfd->fExpandBounds = !!IsDlgButtonChecked(hDlg, IDC_EXPANDBOUNDS);
  704.                 mfd->ifp->RedoSystem();
  705.                 return TRUE;
  706.  
  707.  
  708.             case IDC_PICKCOLOR:
  709.                 mfd->ifp->UndoSystem();
  710.                 if (guiChooseColor(hDlg, mfd->rgbColor)) {
  711.                     DeleteObject(mfd->hbrColor);
  712.                     mfd->hbrColor = CreateSolidBrush(mfd->rgbColor);
  713.                     RedrawWindow(GetDlgItem(hDlg, IDC_COLOR), NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
  714.                 }
  715.                 mfd->ifp->RedoSystem();
  716.                 break;
  717.             }
  718.             break;
  719.  
  720.         case WM_CTLCOLORSTATIC:
  721.             if (GetWindowLong((HWND)lParam, GWL_ID) == IDC_COLOR)
  722.                 return (BOOL)mfd->hbrColor;
  723.             break;
  724.     }
  725.     return FALSE;
  726. }
  727.  
  728. static int rotate2_config(FilterActivation *fa, const FilterFunctions *ff, HWND hWnd) {
  729.     MyFilterData *mfd = (MyFilterData *)fa->filter_data;
  730.     MyFilterData mfd2 = *mfd;
  731.     int ret;
  732.  
  733.     mfd->hbrColor = NULL;
  734.     mfd->ifp = fa->ifp;
  735.  
  736.     ret = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER_ROTATE2), hWnd, rotate2DlgProc, (LONG)mfd);
  737.  
  738.     if (mfd->hbrColor)
  739.         DeleteObject(mfd->hbrColor);
  740.  
  741.     if (ret)
  742.         *mfd = mfd2;
  743.  
  744.     return ret;
  745. }
  746.  
  747. ///////////////////////////////////////////
  748.  
  749. static int rotate2_start(FilterActivation *fa, const FilterFunctions *ff) {
  750.     MyFilterData *mfd = (MyFilterData *)fa->filter_data;
  751.  
  752.     // Compute step parameters.
  753.  
  754.     double ang = mfd->angle * (3.14159265358979323846 / 2147483648.0);
  755.     double ustep = cos(ang);
  756.     double vstep = -sin(ang);
  757.     __int64 du, dv;
  758.  
  759.     mfd->u_step = du = (__int64)floor(ustep*4294967296.0 + 0.5);
  760.     mfd->v_step = dv = (__int64)floor(vstep*4294967296.0 + 0.5);
  761.  
  762.     if (!(mfd->rows = (RotateRow *)callocmem(sizeof(RotateRow), fa->dst.h)))
  763.         return 1;
  764.  
  765.     // It's time for Mr.Bonehead!!
  766.  
  767.     int x0, x1, x2, x3, y;
  768.     __int64 xaccum, yaccum;
  769.     __int64 xaccum_low, yaccum_low, xaccum_high, yaccum_high, xaccum_base, yaccum_base;
  770.     __int64 xaccum_low2, yaccum_low2, xaccum_high2, yaccum_high2;
  771.     RotateRow *rr = mfd->rows;
  772.  
  773.     // Compute allowable source bounds.
  774.  
  775.     xaccum_base = xaccum_low = -0x80000000i64*fa->src.w;
  776.     yaccum_base = yaccum_low = -0x80000000i64*fa->src.h;
  777.     xaccum_high = 0x80000000i64*fa->src.w;
  778.     yaccum_high = 0x80000000i64*fa->src.h;
  779.  
  780.     // Compute accumulators for top-left destination position.
  781.  
  782.     xaccum = ( dv*(fa->dst.h-1) - du*(fa->dst.w-1))/2;
  783.     yaccum = (-du*(fa->dst.h-1) - dv*(fa->dst.w-1))/2;
  784.  
  785.     // Compute 'marginal' bounds that require partial clipping.
  786.  
  787.     switch(mfd->filtmode) {
  788.     case FILTMODE_POINT:
  789.         xaccum_low2 = xaccum_low;
  790.         yaccum_low2 = yaccum_low;
  791.         xaccum_high2 = xaccum_high;
  792.         yaccum_high2 = yaccum_high;
  793.         break;
  794.     case FILTMODE_BILINEAR:
  795.         xaccum_low2 = xaccum_low;
  796.         yaccum_low2 = yaccum_low;
  797.         xaccum_high2 = xaccum_high - 0x100000000i64;
  798.         yaccum_high2 = yaccum_high - 0x100000000i64;
  799.         xaccum_low -= 0x100000000i64;
  800.         yaccum_low -= 0x100000000i64;
  801.  
  802.         xaccum -= 0x80000000i64;
  803.         yaccum -= 0x80000000i64;
  804.         break;
  805.  
  806.     case FILTMODE_BICUBIC:
  807.         xaccum_low2  = xaccum_low  + 0x100000000i64;
  808.         yaccum_low2  = yaccum_low  + 0x100000000i64;
  809.         xaccum_high2 = xaccum_high - 0x200000000i64;
  810.         yaccum_high2 = yaccum_high - 0x200000000i64;
  811.         xaccum_low -= 0x100000000i64;
  812.         yaccum_low -= 0x100000000i64;
  813.  
  814.         xaccum -= 0x80000000i64;
  815.         yaccum -= 0x80000000i64;
  816.         break;
  817.     }
  818.  
  819.     for(y=0; y<fa->dst.h; y++) {
  820.         __int64 xa, ya;
  821.  
  822.         xa = xaccum;
  823.         ya = yaccum;
  824.  
  825.         for(x0=0; x0<fa->dst.w; x0++) {
  826.             if (xa >= xaccum_low && ya >= yaccum_low && xa < xaccum_high && ya < yaccum_high)
  827.                 break;
  828.  
  829.             xa += du;
  830.             ya += dv;
  831.         }
  832.  
  833.         rr->xaccum_left = xa - xaccum_base;
  834.         rr->yaccum_left = ya - yaccum_base;
  835.  
  836.         for(x1=x0; x1<fa->dst.w; x1++) {
  837.             if (xa >= xaccum_low2 && ya >= yaccum_low2 && xa < xaccum_high2 && ya < yaccum_high2)
  838.                 break;
  839.  
  840.             xa += du;
  841.             ya += dv;
  842.         }
  843.  
  844.         for(x2=x1; x2<fa->dst.w; x2++) {
  845.             if (xa < xaccum_low2 || ya < yaccum_low2 || xa >= xaccum_high2 || ya >= yaccum_high2)
  846.                 break;
  847.  
  848.             xa += du;
  849.             ya += dv;
  850.         }
  851.  
  852.         for(x3=x2; x3<fa->dst.w; x3++) {
  853.             if (xa < xaccum_low || ya < yaccum_low || xa >= xaccum_high || ya >= yaccum_high)
  854.                 break;
  855.  
  856.             xa += du;
  857.             ya += dv;
  858.         }
  859.  
  860.         rr->leftzero = x0;
  861.         rr->left = x1-x0;
  862.         rr->right = x3-x2;
  863.         rr->rightzero = fa->dst.w - x3;
  864.         ++rr;
  865.  
  866.         xaccum -= dv;
  867.         yaccum += du;
  868.     }
  869.  
  870.     // Fill out cubic interpolation coeff. table
  871.  
  872.     if (mfd->filtmode == FILTMODE_BICUBIC) {
  873.         if (!(mfd->coeff_tbl = (int *)allocmem(sizeof(int)*256*4)))
  874.             return 1;
  875.  
  876.         MakeCubic4Table(mfd->coeff_tbl, -0.75, !!MMX_enabled);
  877.         
  878.     }
  879.  
  880.     return 0;
  881. }
  882.  
  883. static int rotate2_end(FilterActivation *fa, const FilterFunctions *ff) {
  884.     MyFilterData *mfd = (MyFilterData *)fa->filter_data;
  885.  
  886.     freemem(mfd->rows); mfd->rows = NULL;
  887.     freemem(mfd->coeff_tbl); mfd->coeff_tbl = NULL;
  888.  
  889.     return 0;
  890. }
  891.  
  892. static void rotate2_string(const FilterActivation *fa, const FilterFunctions *ff, char *buf) {
  893.     MyFilterData *mfd = (MyFilterData *)fa->filter_data;
  894.  
  895.     sprintf(buf, " (%.3f\xb0, %s, #%06X%s)",
  896.             mfd->angle * (360.0 / 4294967296.0),
  897.             szModeStrings[mfd->filtmode],
  898.             ColorRefToPixel32(mfd->rgbColor),
  899.             mfd->fExpandBounds ? ", expand" : "");
  900. }
  901.  
  902. static void rotate2_script_config(IScriptInterpreter *isi, void *lpVoid, CScriptValue *argv, int argc) {
  903.     FilterActivation *fa = (FilterActivation *)lpVoid;
  904.     MyFilterData *mfd = (MyFilterData *)fa->filter_data;
  905.  
  906.     mfd->angle        = argv[0].asInt()<<8;
  907.     mfd->filtmode    = argv[1].asInt();
  908.     mfd->rgbColor    = ColorRefToPixel32(argv[2].asInt());
  909.     mfd->fExpandBounds = !!argv[3].asInt();
  910.  
  911.     if (mfd->filtmode < 0)
  912.         mfd->filtmode = 0;
  913.     else if (mfd->filtmode >= FILTMODE_COUNT)
  914.         mfd->filtmode = FILTMODE_COUNT-1;
  915. }
  916.  
  917. static ScriptFunctionDef rotate2_func_defs[]={
  918.     { (ScriptFunctionPtr)rotate2_script_config, "Config", "0iiii" },
  919.     { NULL },
  920. };
  921.  
  922. static CScriptObject rotate2_obj={
  923.     NULL, rotate2_func_defs
  924. };
  925.  
  926. static bool rotate2_script_line(FilterActivation *fa, const FilterFunctions *ff, char *buf, int buflen) {
  927.     MyFilterData *mfd = (MyFilterData *)fa->filter_data;
  928.  
  929.     _snprintf(buf, buflen, "Config(%d, %d, 0x%06X, %d)", (mfd->angle+0x80)>>8, mfd->filtmode,
  930.         ColorRefToPixel32(mfd->rgbColor), mfd->fExpandBounds?1:0);
  931.  
  932.     return true;
  933. }
  934.  
  935. FilterDefinition filterDef_rotate2={
  936.     0,0,NULL,
  937.     "rotate2",
  938.     "Rotates an image by an arbitrary angle."
  939. #ifdef USE_ASM
  940.             "\n\n[Assembly optimized] [MMX optimized]"
  941. #endif
  942.         ,
  943.     NULL,NULL,
  944.     sizeof(MyFilterData),
  945.     NULL,NULL,
  946.     rotate2_run,
  947.     rotate2_param,
  948.     rotate2_config,
  949.     rotate2_string,
  950.     rotate2_start,
  951.     rotate2_end,
  952.  
  953.     &rotate2_obj,
  954.     rotate2_script_line,
  955. };
  956.